﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace Noris.Tools.TraceVisualiser.BlockingVisualiser.Components
{
	internal class LockInfoList : System.Windows.Forms.ListView
	{
		public LockInfoList() : base()
        {
            this.Alignment = ListViewAlignment.Left;
            this.AllowColumnReorder = false;
            this.FullRowSelect = true;
            this.GridLines = false;
            this.HeaderStyle = ColumnHeaderStyle.Nonclickable;
            this.HideSelection = true;
            this.CheckBoxes = false;
            this.LabelEdit = false;
            this.LabelWrap = false;
            this.MultiSelect = false;
            this.Scrollable = true;
            this.ShowGroups = true;
            this.ShowItemToolTips = true;
            this.View = View.Details;
            this.Margin = new Padding(6);

            this.Columns.Clear();
            this.Columns.Add(new ColumnHeader() { Text = "Údaj", Width = 80 });
            this.Columns.Add(new ColumnHeader() { Text = "Hodnota", Width = 220 });

            this.ActiveEdge = EdgeType.None;
        }
        /// <summary>
        /// Druh obsaženého objektu, konstanta.
        /// Konstanty jsou uloženy ve třídě LockInfoCreator.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ContentType { get; set; }
        /// <summary>
        /// ID/SPID obsaženého objektu
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ContentId { get; set; }
        /// <summary>
        /// Určuje hranu conrolu, která vystupuje jako aktivní hrana při určování bodů na této hraně v metodě GetPointOnActiveEdge().
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public EdgeType ActiveEdge { get; set; }
        /// <summary>
        /// Metoda vrátí bod na naší aktivní hraně, který je nejvhodnější pro natažení vztahu mezi námi a druhým podobným objektem.
        /// Slouží k určení krajních bodů pro šipky vztahů.
        /// </summary>
        /// <param name="other">Objekt na druhé straně (podle jeho pozice určuji pozici na své straně)</param>
        /// <param name="add">Přídavek k okraji prvku (this.Margin + add)</param>
        /// <param name="clientSize">Velikost celkové plochy</param>
        /// <param name="shrinkRatio">Poměrné zmenšení úsečky: 0 = default = nezmenšovat, 1 = všechny body budou ležet uprostřed naší úsečky</param>
        /// <returns></returns>
        public PointF GetPointOnActiveEdge(Control other, Size clientSize, float add, float shrinkRatio)
        {
            // Bod na naší úsečce musí ležet v takové relativní pozici (na této úsečce), v jakém poměru leží druhý objekt (jeho střed) vzhledem k celkové ploše v našem směru (X nebo Y):
            float ratio = 0f;
            RectangleF otherBound = other.Bounds;
            SizeF clientSizeF = clientSize;
            switch (this.ActiveEdge)
            {
                case EdgeType.Upper:
                case EdgeType.Lower:
                    ratio = ((otherBound.Left + otherBound.Width / 2f) / clientSizeF.Width);
                    break;
                case EdgeType.Right:
                case EdgeType.Left:
                    ratio = ((otherBound.Top + otherBound.Height / 2f) / clientSizeF.Height);
                    break;
                default:
                    ratio = 0.5f;
                    break;
            }

            // Úprava ratio koeficientem shrink:
            if (shrinkRatio >= 1f)
                ratio = 0.5f;
            else if (shrinkRatio > 0f)
            {
                ratio -= 0.5f;                // Posunu ratio do oblasti -0.5 až +0.5
                ratio = ratio * (1f - shrinkRatio);
                ratio += 0.5f;
            }

            // Nyní najdeme naši úsečku a vypočteme bod na ní ležící:
            Rectangle thisBound = this.Bounds;
            Padding margin = this.Margin;
            RectangleF thisBoundF = new RectangleF(thisBound.Left - margin.Left - add, thisBound.Top - margin.Top - add, thisBound.Width + margin.Horizontal + add + add, thisBound.Height + margin.Vertical + add + add);
            switch (this.ActiveEdge)
            {
                case EdgeType.Upper:
                    return new PointF(thisBoundF.X + ratio * thisBoundF.Width, thisBoundF.Y);
                case EdgeType.Lower:
                    return new PointF(thisBoundF.X + ratio * thisBoundF.Width, thisBoundF.Bottom);
                case EdgeType.Right:
                    return new PointF(thisBoundF.Right, thisBoundF.Y + ratio * thisBoundF.Height);
                case EdgeType.Left:
                    return new PointF(thisBoundF.X, thisBoundF.Y + ratio * thisBoundF.Height);
            }
            return new PointF(thisBoundF.X + 0.5f * thisBoundF.Width, thisBoundF.Y + 0.5f * thisBoundF.Height);
        }
        /// <summary>
        /// Strana obdélníku
        /// </summary>
        public enum EdgeType
        {
            None = 0,
            Upper,
            Right,
            Lower,
            Left
        }
	}
    
}
